package cn.zwx.learn.basic.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.retry.annotation.EnableRetry;
import org.springframework.retry.backoff.ExponentialBackOffPolicy;
import org.springframework.retry.policy.SimpleRetryPolicy;
import org.springframework.retry.support.RetryTemplate;

/**
 * @description: 重试配置类
 * @projectName:java-basic
 * @see:cn.zwx.learn.basic.config
 * @author:zhangwenxue
 * @createTime:2020/12/21 9:27
 * @version:1.0
 */
@Configuration
@EnableRetry
public class RetryConfig {


    /**
     * @description 构建Retry对象
     **/
    @Bean
    public RetryTemplate getRetryTemplate(){
        RetryTemplate retryTemplate = new RetryTemplate();
        //NeverRetryPolicy：只允许调用RetryCallback一次，不允许重试
        //AlwaysRetryPolicy：允许无限重试，直到成功，此方式逻辑不当会导致死循环
        //SimpleRetryPolicy：固定次数重试策略，默认重试最大次数为3次，RetryTemplate默认使用的策略
        //TimeoutRetryPolicy：超时时间重试策略，默认超时时间为1秒，在指定的超时时间内允许重试
        //ExceptionClassifierRetryPolicy：设置不同异常的重试策略，类似组合重试策略，区别在于这里只区分不同异常的重试
        //CircuitBreakerRetryPolicy：有熔断功能的重试策略，需设置3个参数openTimeout、resetTimeout和delegate
        //CompositeRetryPolicy：组合重试策略，有两种组合方式，乐观组合重试策略是指只要有一个策略允许重试即可以，
        //悲观组合重试策略是指只要有一个策略不允许重试即可以，但不管哪种组合方式，组合中的每一个策略都会执行
        // SimpleRetryPolicy就属于无状态重试，因为重试是在一个循环中完成的。那么什么会后会出现或者说需要有状态重试呢？通常有两种情况：事务回滚和熔断
        retryTemplate.setRetryPolicy(new SimpleRetryPolicy());
        // 退避策略 就是多久进行重试
        //  initialInterval：初始休眠时间，默认100毫秒
        // multiplier：指定乘数，当前休眠时间*multiplier即为下一次的休眠时间；
        // maxInterval：指定最大休眠时间，默认30秒，避免multiplier过大引起无限期等待
        ExponentialBackOffPolicy backOffPolicy = new ExponentialBackOffPolicy();
        backOffPolicy.setInitialInterval(3000);
        backOffPolicy.setMultiplier(2);
        backOffPolicy.setMaxInterval(15000);
        retryTemplate.setBackOffPolicy(backOffPolicy);
        // 最大重试三次，时间间隔为3,3*2，3*2*2,且时间间隔不大于15s。
        return retryTemplate;
    }
}
